from bdtime import Time
from typing import List, Dict
import bisect


tt = Time()


class IdGenerator:
    def __init__(self):
        self._id = 0

    def get_next_id(self):
        self._id += 1
        return self._id


class RoomIdGenerators:
    def __init__(self):
        self.room_id_generators: Dict[int, IdGenerator] = {}  # {room_id, IdGenerator}

    def get_room_id_generator(self, room_id: int):
        if room_id not in self.room_id_generators:
            self.room_id_generators[room_id] = IdGenerator()
        return self.room_id_generators[room_id]

    def get_next_room_id(self, room_id: int):
        return self.get_room_id_generator(room_id).get_next_id()


room_id_generators = RoomIdGenerators()


class OrderedEventBase:
    def __init__(self,
                 room_id: int = None,
                 event_name: str = None,
                 ordering: (int, float) = 0,
                 event_data: (str, dict) = None,
                 event_id: int = None):
        assert room_id is not None
        self.room_id = room_id
        self.event_id = event_id if event_id else room_id_generators.get_next_room_id(room_id)
        self.event_data = event_data
        self.create_time = tt.now(6)
        self.ordering = ordering

        self._class_name = type(self).__name__
        self.event_name = event_name if event_name else f'{self.class_name}_{self.event_id}'

    @property
    def class_name(self):
        return self._class_name

    def complete_error_msg(self, msg: str, other=None):
        error_msg = f"*** {msg} \nself: {self}"
        if other:
            error_msg += f", \nother: {other}"
        return error_msg

    def __lt__(self, other):
        # 比较事件的时间，用于排序
        assert self.room_id == other.room_id, \
            self.complete_error_msg("Events in different rooms cannot be compared!", other)
        return (self.ordering, self.event_id) < (other.ordering, other.event_id)

    def __repr__(self):
        return f"{self.class_name}(room_id={self.room_id}, event_id={self.event_id}, event_name='{self.event_name}, ordering: {self.ordering}')"

    def run(self):
        msg = f'running on --- {self}'
        if self.event_data:
            msg += f' --- event_data: {self.event_data}'
        print(msg)


class OrderedEventList:
    def __init__(self, room_id: int):
        self.room_id = room_id
        self.events: List[OrderedEventBase] = []  # 存储事件的有序列表

        self.force_correct_room = True  # 是否强制检查事件所属房间

    def add_event(self, event):
        # 将事件插入到正确的位置以保持有序
        if self.force_correct_room:
            event.room_id = self.room_id  # 确保事件属于正确的房间
        bisect.insort(self.events, event)

    def remove_event(self, event):
        # 移除指定的事件
        res = False
        if event in self.events:
            self.events.remove(event)
            res = True
        return res

    def remove_event_by_id(self, event_id: int):
        # 根据事件ID移除事件
        for event in self.events:
            if event.event_id == event_id:
                self.events.remove(event)
                return True
        return False

    def get_event_by_id(self, event_id: int):
        for event in self.events:
            if event.event_id == event_id:
                return event
        return None

    def get_events(self):
        # 返回所有事件
        return self.events

    def pop_next_event(self):
        # 获取并移除最早的事件
        if self.events:
            return self.events.pop(0)
        return None

    def run_all_events(self):
        for event in self.events:
            event.run()


if __name__ == '__main__':
    room_id = 0
    event_list = OrderedEventList(room_id=room_id)

    for i in range(5):
        # e = Event(f"Event_{i + 1}", (3 + i) % 5)
        e = OrderedEventBase(room_id=room_id, ordering=(3 + i) % 5)
        event_list.add_event(e)

    # e = OrderedEventBase(event_name=f"Event_{i + 1}", ordering=-1, room_id=123)
    e = OrderedEventBase(event_name=f"OrderedEventBase{i + 1}", ordering=-1, room_id=room_id)
    event_list.add_event(e)

    event_list.run_all_events()
